package com.bryantkobe.myspringcode.filter;

import com.github.f4b6a3.ulid.UlidCreator;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * @description: MDC过滤器代码
 * @author: alienwarezzl
 * @date: 2025/9/21
 */
@Component
public class MDCFilter implements Filter {

    //常见的链路追踪ID请求头名
    private static final String TRACE_ID_HEADER = "X-Trace-Id";
    //对应log4j2配置中的$X{traceId}
    private static final String TRACE_ID_MDC_KEY = "traceId";

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest,
                         ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;

        try {
            //尝试从请求头获取traceId，如果没有则生成一个ULID
            String traceId = httpRequest.getHeader(TRACE_ID_HEADER);
            if (StringUtils.isBlank(traceId)) {
                traceId = UlidCreator.getUlid().toString();
            }

            //将traceId放入MDC上下文和响应头
            MDC.put(TRACE_ID_MDC_KEY, traceId);
            httpResponse.setHeader(TRACE_ID_HEADER, traceId);

            //继续执行过滤器链
            filterChain.doFilter(servletRequest, servletResponse);
        }finally {
            //确保请求处理后清楚MDC，防止内存泄漏，异步编程中尤为重要
            MDC.clear();
        }
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}
